#include "CustomProt.h"
#include "ModMgr.h"

#define PROT_START_FLAG 0xA5C3
#define PROT_END_FLAG 0x5A3C

enum class ResponseCmd : uint16_t
{
    Prot = (uint16_t)-2,
    Module = (uint16_t)-1,
};

#pragma pack(push, 1)
struct HandShakeResponse
{
    uint16_t nLen;
    ResponseCmd nCmd;
    bool bResult;
};
#pragma pack(pop)

CCustomProt::CCustomProt(/* args */)
{
}

CCustomProt::~CCustomProt()
{
}

// 自定义协议 ProtType::Custom
// 握手协议包：前两个个字节以0xA5C3开始，第三四字节：包长度（模块名称+CRC16长度），
// 第四字节开始：模块名称'\0'为结束符， 倒数三四字节：CRC16值，最后两字节以0x5A3C结束
CCustomProt *CCustomProt::CustomProtParse(CBuffer<> *pBuffer, PkgBuf *pbRecv, ProtModule &pm)
{
    CCustomProt *pPort = nullptr;
    int iBufLen = pBuffer->GetDataLength();

    // 数据流缓冲数据长度不够（包长度）
    if (iBufLen < (int)sizeof(uint16_t))
        return nullptr;

    if (PROT_START_FLAG == *(uint16_t *)pbRecv->pBuffer)
    {
        int iRead = 0;
        uint8_t *ptr = pbRecv->pBuffer;

        // 如果包缓冲只有标头两字节，读三四字节
        if (sizeof(uint16_t) == pbRecv->nCurLen)
        {
            iRead = pBuffer->Read(pbRecv->pBuffer + pbRecv->nCurLen, sizeof(uint16_t));

            if ((int)sizeof(uint16_t) > iRead)
            {
                printf("Error: pBuffer->Read\n");
                return nullptr;
            }

            pbRecv->nCurLen += iRead;
            iBufLen -= iRead;
        }

        ptr += sizeof(uint16_t); // 跳过标头两字节，指向数据长度

        uint16_t nPkgLen = *(uint16_t *)ptr; // 获得数据包长度, TODO:判断长度
        uint16_t nEndFlag = 0;
        uint16_t nNeedRead = nPkgLen + (int)sizeof(uint16_t);

        // 数据流缓冲不够，等下次数据
        if (iBufLen < nNeedRead)
            return nullptr;

        iRead = pBuffer->Read(pbRecv->pBuffer + pbRecv->nCurLen, nNeedRead);

        if (nNeedRead > iRead)
        {
            printf("Error: pBuffer->Read\n");
            return nullptr;
        }

        pbRecv->nCurLen += iRead;
        pbRecv->nPkgLen = pbRecv->nCurLen;
        iBufLen -= iRead;

        ptr += sizeof(uint16_t);                 // 指向模块名称
        nEndFlag = *(uint16_t *)(ptr + nPkgLen); // 指向标尾

        if (PROT_END_FLAG == nEndFlag)
        {
            CModMgr *pModMgr = CModMgr::GetInstance();

            if (nullptr == pModMgr)
                return nullptr;

            // TODO:CRC16数据校验

            pm.pt = ProtType::Custom;
            pm.iMod = pModMgr->GetModuleId((char *)ptr);

            pPort = new CCustomProt();
        }
    }

    return pPort;
}

int8_t CCustomProt::ModuleParse(CBuffer<> *pBuffer, PkgBuf *pbRecv)
{
    return -1;
}

// 数据协议包：数据长度(uint16_t) + 数据
HandleResult CCustomProt::DataParse(CBuffer<> *pBuffer, PkgBuf *pbRecv)
{
    int iRead = 0;
    uint16_t nReadLen = 0;
    int iBufLen = pBuffer->GetDataLength();

    if (0 == pbRecv->nPkgLen)
    {
        if ((int)sizeof(uint16_t) > iBufLen)
            return HandleResult::Fail;

        iRead = pBuffer->Read(pbRecv->pBuffer, sizeof(uint16_t));

        if ((int)sizeof(uint16_t) > iRead)
        {
            printf("Error: pBuffer->Read\n");
            return HandleResult::Error;
        }

        iBufLen -= iRead;
        pbRecv->nPkgLen = *(uint16_t *)pbRecv->pBuffer;
        pbRecv->nCurLen = 0; // 只取数据长度
    }

    if (0 >= iBufLen)
        return HandleResult::Fail;

    nReadLen = (iBufLen + pbRecv->nCurLen > pbRecv->nPkgLen) ? (pbRecv->nPkgLen - pbRecv->nCurLen) : iBufLen;
    iRead = pBuffer->Read(pbRecv->pBuffer + pbRecv->nCurLen, nReadLen);

    if (nReadLen > iRead)
    {
        printf("Error: pBuffer->Read\n");
        return HandleResult::Error;
    }

    pbRecv->nCurLen += iRead;

    return ((pbRecv->nPkgLen == pbRecv->nCurLen) ? HandleResult::Success : HandleResult::Fail);
}

HandleResult CCustomProt::DataHandle(PkgBuf *pbRecv, CClient *pClnt)
{
    return HandleResult::Fail;
}

bool CCustomProt::ProtResponse(PkgBuf *pbSend, bool bResult)
{
    HandShakeResponse hsr;
    hsr.nLen = sizeof(HandShakeResponse) - sizeof(uint16_t);
    hsr.nCmd = ResponseCmd::Prot;
    hsr.bResult = bResult;

    pbSend->nPkgLen = pbSend->nCurLen = sizeof(hsr);
    memcpy(pbSend->pBuffer, &hsr, sizeof(hsr));

    return true;
}

bool CCustomProt::ModuleResponse(PkgBuf *pbSend, bool bResult)
{
    HandShakeResponse hsr;
    hsr.nLen = sizeof(HandShakeResponse) - sizeof(uint16_t);
    hsr.nCmd = ResponseCmd::Module;
    hsr.bResult = bResult;

    pbSend->nPkgLen = pbSend->nCurLen = sizeof(hsr);
    memcpy(pbSend->pBuffer, &hsr, sizeof(hsr));

    return true;
}

uint16_t CCustomProt::PackageData(uint8_t *pDest, uint8_t *pSrc, uint16_t nLen)
{
    *(uint16_t *)pDest = nLen;
    memcpy(pDest + sizeof(uint16_t), pSrc, nLen);

    return nLen + sizeof(uint16_t);
}